package main

import "fmt"

/*
继承
当多个结构体存在相同的属性(字段)和方法时,可以从这些结构体中抽象出结构体,在该结构体中定义这些相同的属性和方法
其他结构体不需要重新定义这些属性和方法,只需要嵌套一个匿名结构体即可.也就是说在golang中,如果一个struct嵌套了
另一个匿名结构体,那么这个结构体可以直接访问匿名结构体的字段和方法,从而实现了继承的特性

1.结构体可以使用嵌套匿名结构体所有的字段和方法,即:首字母大写或者小写的字段,方法都可以使用
2.匿名结构体字段访问可以简化
3.当结构体和匿名结构体有相同的字段或者方法时,编译器采用就近访问原则访问,如希望访问匿名结构体的字段和方法
可以通过匿名结构体名来区分
4.(不推荐使用)golang中支持多继承,如一个结构体嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套的匿名结构体的字段和方法
从而实现了多重继承. 为了保证代码的简洁性,建议尽量不使用多重继承,很多语言已将多重继承去除了
5.如嵌入的匿名结构体有相同的字段名或者方法名,则在访问时,需要通过匿名结构体的类型名来区分
6.结构体的匿名字段是基本数据类型
7.嵌套匿名结构体后,也可以在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值
8.嵌入匿名结构体的指针也是可以的
9.结构体的字段可以是结构体类型的(组合模式)
*/

type Animal struct {
	Age int
	//即便小写也能被 Cat 的匿名结构体进行访问
	weight float32
}

func (an *Animal) Shout() {
	fmt.Println("我可以大声喊叫")
}

func (an *Animal) ShowInfo() {
	fmt.Printf("动物的年龄是: %v, 动物的体重是: %v", an.Age, an.weight)
	fmt.Println()
}

type Cat struct {
	//为了复用性体现继承思维,加入匿名结构体
	Animal
}

//对Cat绑定的特有方法
func (c *Cat) scratch() {
	fmt.Println("我是小猫,我会挠人")
}

func (c *Cat) ShowInfo() {
	fmt.Printf("小猫的年龄是: %v, 小猫的体重是: %v", c.Age, c.weight)
	fmt.Println()
}

func main() {
	//创建Cat结构体示例
	cat := &Cat{}
	//可以携带匿名结构体名
	cat.Animal.Age = 3
	//也可以不携带匿名结构体名
	cat.weight = 10.61
	cat.Animal.Shout()
	//优先在当前结构体找可执行的方法
	cat.ShowInfo()
	cat.Animal.ShowInfo()
	cat.scratch()
}
